#include "GammaFilter.h"
#include "FilterException.h"
#include <cv.h>
#include <math.h>

using namespace cv;

GammaFilter::GammaFilter(double gamma): gamma(gamma){}

//FIXME Para valores de >1 verificar porque no anda
void GammaFilter::process(const Mat& src, Mat& dst)
{
	//chequeo que el tipo de matrices sea válido
	if ((src.type() != CV_8UC3) && !(src.type() != CV_8UC4))
		throw FilterException("src debe ser de tipo CV_8UC3 o CV_8UC4");
	if (src.type() != dst.type() || src.size() != dst.size())
		throw FilterException("dst debe ser del mismo tipo y tamaño que src");

    vector<Mat> planes;
    split(src, planes);

    for(unsigned int k = 0; k < planes.size(); ++k)
    {
    	unsigned char min = 255;
    	unsigned char max = 0;

    	for(int i = 0; i < src.rows; ++i)
    	{
			uchar* ptrP = planes[k].ptr<uchar>(i);
			for(int j = 0; j < src.cols; ++j)
			{
				if (ptrP[j] < min) min = ptrP[j];
				if (ptrP[j] > max) max = ptrP[j];
			}
		}

    	double a = pow(min,gamma);
    	double b = pow(max, gamma);

    	double scale = 	1.0 / (b - a);
    	short shifts = min - 1;

    	for(int i = 0; i < src.rows; ++i)
    	{
  			uchar* ptrP = planes[k].ptr<uchar>(i);
    		for(int j = 0; j < src.cols; ++j)
    		{
    			double tmpVal = ptrP[j];
    			tmpVal = (tmpVal - shifts) * scale;
    			tmpVal = (uchar)pow(ptrP[j],gamma);
    			short data = tmpVal;

				if (data > 255)
					data = 255;
				if (data < 0)
					data = 0;

    			ptrP[j] = (uchar)data;
    		}
    	}
	}

	merge(planes, dst);
}
